import grok
from persistent.dict import PersistentDict
from zope.interface import Interface
from zope import schema
from zope.app.container.interfaces import INameChooser

class FinancialHistory(grok.Application, grok.Container):
    def __init__(self, initialBalance=0):
        super(FinancialHistory, self).__init__()
        self.cashOnHand = initialBalance
        self.incomes = PersistentDict()

    def receiveFrom(self, source, amount):
        self.incomes[source] = self.totalReceivedFrom(source) + amount
        self.cashOnHand += amount
        
    def spendFor(self, reason, amount):
        self[reason] = self.totalSpentFor(reason) + amount
        self.cashOnHand -= amount
        
    def totalReceivedFrom(self, source):
        return self.incomes.get(source, 0)
    
    def totalSpentFor(self, reason):
        total = 0.0
        for object in self.values():
            if isinstance(object, Expense):
                if object.reason == reason:
                    total += object.amount
        return total


class Index(grok.View):
    grok.context(FinancialHistory)
    
    def cashOnHand(self):
        return '%0.2f' % (self.context.cashOnHand)

    def update(self, source=None, amount=None):
        if source is not None:
            self.context.receiveFrom(source,float(amount))

    def listIncome(self):
        return [{'source':k, 'amount': '%0.2f'%v} 
            for k,v in self.context.incomes.items()]

    def listExpenses(self):
        return self.context.values()
            
class IExpense(Interface):
    reason = schema.TextLine(title=u"Reason",
                             required=True)
    amount = schema.Float(title=u"Amount",
                          required=True,
                          constraint=lambda x: x>0)
    audited = schema.Bool(title=u"Audited",
                             required=False,
                             default=False)                                 
            
class Expense(grok.Model):
    grok.implements(IExpense)
    
    def __init__(self, reason, amount, audited=False):
        self.reason = reason
        self.amount = amount
        self.audited = audited
    
class Edit(grok.EditForm):
    grok.context(Expense)
    pass
    
class AddExpense(grok.AddForm):
    grok.context(FinancialHistory)
    
    form_fields = grok.AutoFields(IExpense).omit('date')

    @grok.action('Save')
    def add(self, **data):
        name = data['reason'].replace(' ','_')
        expense = Expense(**data)
        name = INameChooser(self.context).chooseName(name, expense)        
        self.context[name] = expense
        self.redirect(self.application_url())
        
@grok.subscribe(IExpense, grok.IObjectAddedEvent)
def bookAdded(expense, event):
    account = expense.__parent__
    account.cashOnHand -= expense.amount
